<!DOCTYPE html>
<html>
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
  <script src="scroll_support.js"></script>
  <body>
    <style>
      .scroller {
        scroll-snap-type: x mandatory;
        overflow-x: auto;
        overflow-y: hidden;
        position: relative;
        height: 500px;
        width: 500px;
      }

      .box {
        scroll-snap-align: start;
        width: 400px;
        position: absolute;
        top: 200px;
      }

      #box1 {
        background-color: red;
        height: 500px;
      }

      #box2 {
        background-color: yellow;
        height: 300px;
        left: 700.5px;
      }

      #box3 {
        background-color: blue;
        height: 100px;
        left: 1400px;
      }
    </style>
    <div id="scroller" class="scroller">
      <div class="box" id="box1">1</div>
      <div class="box" id="box2">2</div>
      <div class="box" id="box3">3</div>
    </div>
    <script>
      let scrollendCount = 0;
      scroller.addEventListener('scrollend', () => {
        scroller.style.maxHeight = null;
        scroller.style.maxHeight = `${box2.clientHeight}px`;
        scrollendCount += 1;
      });
      promise_test(async (test) => {
        // This test aims to verify that scrollend fires correctly (i.e. once)
        // when the target snap position is not a whole number. In this case, we
        // expect to snap to the left edge of box2 which is at a fractional
        // offset from the scroller's origin (left: 700.5px).
        // The scroll offset resulting from the snap may not be fractional
        // (e.g. if the browser does not support fractional scroll offsets) so
        // we verify the scroll offset with assert_approx_equals.
        assert_equals(scroller.scrollLeft, 0,
        "test precondition: scroller is not scrolled.");
        const expected_scroll_left = box2.offsetLeft;
        const target_offset = box2.offsetLeft + box2.clientWidth / 2;

        let scrollend_promise = waitForScrollendEvent(test, scroller);
        scroller.scrollTo( { left: target_offset });
        await scrollend_promise;

        // Instead of a time-based wait for errant scrollends, we wait a frame
        // and then scroll back to 0.
        await waitForCompositorCommit();
        assert_approx_equals(scroller.scrollLeft, expected_scroll_left, 1,
            "scroller snaps to the left edge of box 2");

        scrollend_promise = waitForScrollendEvent(test, scroller);
        scroller.scrollTo({ left: 0 });
        await scrollend_promise;
        assert_equals(scroller.scrollLeft, 0,
            "scroller should be scrolled back to 0.");
        assert_equals(scrollendCount, 2, "exactly 2 scrollends should be seen");
      }, "snap to fractional offset fires scrollend exactly once.");
    </script>
  </body>
</html>